package cn.baiweigang.uu.service.linearswap;

import cn.baiweigang.uu.api.linearswap.TradeApi;
import cn.baiweigang.uu.enums.*;
import cn.baiweigang.uu.model.*;
import cn.baiweigang.uu.utils.DateUtil;
import cn.baiweigang.uu.utils.LogUtil;
import cn.baiweigang.uu.utils.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

@Service
public class OrderService {
    @Autowired
    private TradeApi tradeApi;
    @Autowired
    private AccountService accountService;

    /**
     * 闪电平掉持仓
     *
     * @param accountInfo
     */
    public void forceCleanPosition(AccountInfo accountInfo) {
        LogUtil.logInfo("获取当前持仓");
        accountService.updateAccountFromHB(accountInfo);
        List<PositionInfo> positionInfoList = accountInfo.getPositionInfo();
        if (positionInfoList != null && positionInfoList.size() > 0) {
            TradeInfo tradeInfo = new TradeInfo();
            tradeInfo.setContractCode(accountInfo.getContractCode());
            tradeInfo.setMarginMode(accountInfo.getMarginMode());
            tradeInfo.setAccountName(accountInfo.getAccountName());
            for (PositionInfo positionInfo : positionInfoList) {
                tradeInfo.setVolume(positionInfo.getVolume());
                tradeInfo.setDirection(positionInfo.getDirection());
                forceCleanPosition(tradeInfo);
            }
        } else {
            LogUtil.logInfo("持仓为空，无需强平");
        }
    }

    public void forceCleanPosition(TradeInfo tradeInfo) {
        TradeInfo tmp = new TradeInfo();
        tmp.setContractCode(tradeInfo.getContractCode());
        tmp.setMarginMode(tradeInfo.getMarginMode());
        tmp.setAccountName(tradeInfo.getAccountName());
        tmp.setVolume(tradeInfo.getVolume());
        tmp.setDirection(tradeInfo.getDirection() == DirectionEnum.BUY ? DirectionEnum.SELL : DirectionEnum.BUY);

        boolean result = tradeApi.lightningClose(tmp);
        LogUtil.logInfo("强制平仓提交结果 " + result);
    }

    public boolean isExistOpenOrders(AccountInfo accountInfo) {
        //委托单
        List<TradeInfo> openOrders = tradeApi.queryOpenOrders(accountInfo.getAccountName(),
                accountInfo.getContractCode(), TradeTypeEnum.ALL);
        //计划委托单
        List<TradeInfo> triggerOpenOrders = tradeApi.queryTriggerOpenOrders(accountInfo.getAccountName(),
                accountInfo.getContractCode(), TradeTypeEnum.ALL);
        //止盈止损单
        List<TradeInfo> tpslOpenOrders = tradeApi.queryTpslOpenOrders(accountInfo.getAccountName(),
                accountInfo.getContractCode());

        return isEmptyList(openOrders) || isEmptyList(triggerOpenOrders) ||
                isEmptyList(tpslOpenOrders);
    }

    public void cancelAllOpenOrders(AccountInfo accountInfo) {
        tradeApi.orderCancelAll(accountInfo.getAccountName(), accountInfo.getMarginMode(), accountInfo.getContractCode());
        tradeApi.triggerOrderCancelAll(accountInfo.getAccountName(), accountInfo.getMarginMode(), accountInfo.getContractCode());
        tradeApi.tpslOrderCancelAll(accountInfo.getAccountName(), accountInfo.getMarginMode(), accountInfo.getContractCode());
    }

    public void cancelOpenOrders(AccountInfo accountInfo) {
        tradeApi.orderCancelAll(accountInfo.getAccountName(), accountInfo.getMarginMode(), accountInfo.getContractCode());
    }


    private boolean isEmptyList(List list) {
        return list != null && list.size() > 0;
    }

    public boolean orderRequest(TradeInfo tradeInfo) {
        boolean result = tradeApi.orderRequest(tradeInfo);
        LogUtil.logInfo("开仓委托单提交结果：" + result);
        return result;
    }


    public void cancelIfExist(AccountInfo accountInfo) {
        //检查是否有委托单，有的话需要撤单
        if (isExistOpenOrders(accountInfo)) {
            LogUtil.logInfo("账号：" + accountInfo.getAccountName() +
                    "存在挂单，需要撤单");
            cancelAllOpenOrders(accountInfo);
        }
    }

    public void forceIfExist(AccountInfo accountInfo) {
        //检查持仓情况
        if (accountInfo.getPositionInfo() != null && accountInfo.getPositionInfo().size() > 0) {
            LogUtil.logInfo("账号：" + accountInfo.getAccountName() +
                    "持仓不为空，需要平仓");
            //平仓操作
            forceCleanPosition(accountInfo);
        }
    }

    public void openOrder(StrategyInfo strategyInfo,
                          DirectionEnum direction, KLineInfo kLineInfo) {
        //防止重复提交委托单 判断状态
        if (strategyInfo.getOpenOrder() != null &&
                strategyInfo.getOpenOrder().getStatus() == TradeStatusEnum.INIT) {
            LogUtil.logError("当前已经存在处理中的委托单了 不允许重复提交");
        } else {
            AccountInfo accountInfo = strategyInfo.getAccountInfo();
            //判断是否有持仓，如果有，则先强平掉
            forceCleanPosition(accountInfo);
            TradeInfo tradeInfo = new TradeInfo();
            tradeInfo.setClientOrderId(DateUtil.formatDate(new Date(), "yyyyMMddHHmmss") + StringUtil.getRandom(4));
            tradeInfo.setAccountName(accountInfo.getAccountName());
            tradeInfo.setMarginMode(accountInfo.getMarginMode());
            tradeInfo.setContractCode(accountInfo.getContractCode());
            tradeInfo.setVolume(accountInfo.getOpenVolume());
            tradeInfo.setOffset(OffsetEnum.OPEN);
            tradeInfo.setLeverRate(accountInfo.getLeverRate());
            tradeInfo.setOrderPriceType(OrderPriceTypeEnum.limit);
            tradeInfo.setTpOrderPriceType(OrderPriceTypeEnum.optimal_20);
            tradeInfo.setSlOrderPriceType(OrderPriceTypeEnum.optimal_20);
            tradeInfo.setPrice(kLineInfo.getClose());
            tradeInfo.setStatus(TradeStatusEnum.INIT);
            //订单方向
            tradeInfo.setDirection(direction);
            if (direction == DirectionEnum.BUY) {
                //止盈
                tradeInfo.setTpTriggerPrice(tradeInfo.getPrice().add(BigDecimal.valueOf(strategyInfo.getTp())));
                tradeInfo.setTpOrderPrice(tradeInfo.getPrice().add(BigDecimal.valueOf(strategyInfo.getTp())));
                //止损
                tradeInfo.setSlTriggerPrice(tradeInfo.getPrice().subtract(BigDecimal.valueOf(strategyInfo.getSl())));
                tradeInfo.setSlOrderPrice(tradeInfo.getPrice().subtract(BigDecimal.valueOf(strategyInfo.getSl())));
            } else {
                //止盈
                tradeInfo.setTpTriggerPrice(tradeInfo.getPrice().subtract(BigDecimal.valueOf(strategyInfo.getTp())));
                tradeInfo.setTpOrderPrice(tradeInfo.getPrice().subtract(BigDecimal.valueOf(strategyInfo.getTp())));
                //止损
                tradeInfo.setSlTriggerPrice(tradeInfo.getPrice().add(BigDecimal.valueOf(strategyInfo.getSl())));
                tradeInfo.setSlOrderPrice(tradeInfo.getPrice().add(BigDecimal.valueOf(strategyInfo.getSl())));
            }

            if (orderRequest(tradeInfo)) {
                strategyInfo.setOpenOrder(tradeInfo);
            }
        }
    }

    public boolean tpslOrderCancelAll(AccountInfo accountInfo) {
        return tradeApi.tpslOrderCancelAll(accountInfo.getAccountName(), accountInfo.getMarginMode(), accountInfo.getContractCode());
    }

    public boolean tpslOrderRequest(StrategyInfo strategyInfo, int slVolume) {
        TradeInfo tradeInfo = new TradeInfo();
        tradeInfo.setAccountName(strategyInfo.getAccountInfo().getAccountName());
        tradeInfo.setMarginMode(strategyInfo.getAccountInfo().getMarginMode());
        tradeInfo.setContractCode(strategyInfo.getAccountInfo().getContractCode());
        tradeInfo.setVolume(strategyInfo.getOpenOrder().getVolume());
        tradeInfo.setTpOrderPriceType(OrderPriceTypeEnum.optimal_20);
        tradeInfo.setSlOrderPriceType(OrderPriceTypeEnum.optimal_20);

        BigDecimal price = strategyInfo.getOpenOrder().getPrice();
        //重新设置止损价
        if (strategyInfo.getOpenOrder().getDirection() == DirectionEnum.BUY) {
            tradeInfo.setDirection(DirectionEnum.SELL);
            //止盈
            tradeInfo.setTpTriggerPrice(price.add(BigDecimal.valueOf(strategyInfo.getTp())));
            tradeInfo.setTpOrderPrice(price.add(BigDecimal.valueOf(strategyInfo.getTp())));

            //止损
            tradeInfo.setSlTriggerPrice(price.add(BigDecimal.valueOf(slVolume)));
            tradeInfo.setSlOrderPrice(price.add(BigDecimal.valueOf(slVolume)));
        } else {
            tradeInfo.setDirection(DirectionEnum.BUY);
            //止盈
            tradeInfo.setTpTriggerPrice(price.subtract(BigDecimal.valueOf(strategyInfo.getTp())));
            tradeInfo.setTpOrderPrice(price.subtract(BigDecimal.valueOf(strategyInfo.getTp())));

            //止损
            tradeInfo.setSlTriggerPrice(price.subtract(BigDecimal.valueOf(slVolume)));
            tradeInfo.setSlOrderPrice(price.subtract(BigDecimal.valueOf(slVolume)));
        }
        List<TradeInfo> tradeInfoList = tradeApi.tpslOrderRequest(tradeInfo);
        if (tradeInfoList != null) {
            strategyInfo.getOpenOrder().setSlOrderPrice(tradeInfo.getSlOrderPrice());
            strategyInfo.getOpenOrder().setSlTriggerPrice(tradeInfo.getSlTriggerPrice());
            return true;
        }
        return false;
    }
}
